package com.regent.central.bill.web.sale_order;

import com.regent.central.bill.common.ActionType;
import com.regent.central.bill.core.*;
import com.regent.central.bill.service.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 销售单操作记录控制器
 *
 * @author 杨昌沛 646742615@qq.com
 * @date 2018-06-27 16:39
 **/
@Controller
@RequestMapping("/sale-order-actions")
public class SaleOrderActionController {

    @Resource
    private SaleOrderService saleOrderService;

    @Resource
    private SaleOrderActionService saleOrderActionService;

    @Resource
    private CreateGoodsService createGoodsService;

    @Resource
    private ModifyGoodsService modifyGoodsService;

    @Resource
    private ReturnGoodsService returnGoodsService;

    @Resource
    private RemittanceService remittanceService;

    @Resource
    private ClearanceService clearanceService;

    @Resource
    private DeliveryGoodsService deliveryGoodsService;

    @Resource
    private DeliveryActionService deliveryActionService;

    /**
     * 撤销开单货品
     *
     * @param request 撤销动作货品请求
     * @return 撤销动作货品结果
     */
    @RequestMapping(value = "/create-goods", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelCreateGoods(
            SaleOrderActionCancelRequest request
    ) {
        String saleOrderId = request.getSaleOrderId();
        String actionId = request.getActionId();
        String userId = request.getUserId();
        // 如果销售单有被改欠货记录而且还没撤销的, 则不能撤销销售单的开单货品
        List<SaleOrderAction> actions = saleOrderActionService.listByOrderIdAndActionType(saleOrderId, ActionType.MODIFY_THIS);
        if (actions != null && !actions.isEmpty()) {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            response.setCode(400);
            response.setMessage("销售单存在被改欠货, 不允许撤销!");
            return response;
        }
        return saleOrderActionService.doAtomically(() -> {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

            if (action == null || action.getActionType() != ActionType.CREATE) {
                response.setCode(400);
                response.setMessage("操作记录不存在");
                return response;
            }

            // 撤销销售单开单货品动作主记录
            saleOrderActionService.cancel(actionId, userId);
            // 撤销销售单开单货品动作子记录
            saleOrderActionService.cancelChildren(actionId, userId);

            // 删除开单货品
            createGoodsService.deleteForSaleOrderCreateAction(actionId, userId);
            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

    /**
     * 撤销改他单货品
     *
     * @param request 撤销动作货品请求
     * @return 撤销动作货品结果
     */
    @RequestMapping(value = "/modify-that-goods", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelModifyThatGoods(
            SaleOrderActionCancelRequest request
    ) {
        SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
        SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());
        if (action == null || action.getActionType() != ActionType.MODIFY_THAT) {
            response.setCode(400);
            response.setMessage("操作记录不存在");
            return response;
        }

        // 将改欠货数据恢复之后被改欠货的销售单的要货数还是否大于发货数
        String saleOrderId = action.getActionId();
        // 1. 获取被改欠货销售单的开单货品列表
        List<CreateGoods> creates = createGoodsService.getSaleOrderCreateGoods(saleOrderId);
        // 2. 获取被改欠货销售单的发货货品列表
        List<DeliveryGoods> deliveries = deliveryGoodsService.getSaleOrderDeliveryGoods(saleOrderId);
        // 3. 获取本动作的改欠货货品列表
        List<ModifyGoods> modifies = modifyGoodsService.getSaleOrderModifyGoodsOfParent(request.getActionId());
        // 判断每个SKU的(要货数 - 改欠货数 - 发货数 >= 0)
        // 定义一个Map
        Map<String, BigDecimal> map = new HashMap<>();
        // 1. 把要货数放进去
        Map<String, BigDecimal> m = creates.stream().map(CreateGoods::getSkus).flatMap(Collection::stream).collect(Collectors.toMap(CreateGoodsSKU::getSkuId, CreateGoodsSKU::getQuantity));
        map.putAll(m);
        // 2. 减去改欠货数
        modifies.stream().map(ModifyGoods::getSkus).flatMap(Collection::stream).forEach(sku -> {
            BigDecimal quantity = map.get(sku.getSkuId());
            if (quantity == null) return;
            quantity = quantity.subtract(sku.getQuantity());
            map.put(sku.getSkuId(), quantity);
        });
        // 3. 减去发货数
        deliveries.stream().map(DeliveryGoods::getSkus).flatMap(Collection::stream).forEach(sku -> {
            BigDecimal quantity = map.get(sku.getSkuId());
            if (quantity == null) return;
            quantity = quantity.subtract(sku.getQuantity());
            map.put(sku.getSkuId(), quantity);
        });
        // 4. 判断每个value是否依然大于BigDecimal.ZERO
        boolean denied = map.values().stream().anyMatch(value -> value.compareTo(BigDecimal.ZERO) < 0);
        // 如果不满足
        if (denied) {
            response.setCode(400);
            response.setMessage("已发货数将大于要货数!");
            return response;
        }

        String orderId = request.getSaleOrderId();
        String actionId = request.getActionId();
        String userId = request.getUserId();
        return saleOrderActionService.doAtomically(() -> {

            // 撤销销售单的改他单动作主记录
            saleOrderActionService.cancel(actionId, userId);
            // 撤销销售单改他单动作子记录
            saleOrderActionService.cancelChildren(actionId, userId);
            // 删除改他单货品
            modifyGoodsService.deleteForSaleOrderModifyAction(actionId, userId);

            // 被改单的改本单动作主记录
            SaleOrderAction parent = saleOrderActionService.selectBy(ActionType.MODIFY_THIS, orderId);
            // 撤销被改单的改本单动作主记录
            saleOrderActionService.cancel(parent.getId(), userId);
            // 撤销被改单的改本单动作子记录
            saleOrderActionService.cancelChildren(parent.getId(), userId);

            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

    /**
     * 撤销改本单货品
     *
     * @param request 撤销动作货品请求
     * @return 撤销动作货品结果
     */
    @RequestMapping(value = "/modify-this-goods", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelModifyThisGoods(
            SaleOrderActionCancelRequest request
    ) {
        SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
        SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

        if (action == null || action.getActionType() != ActionType.MODIFY_THIS) {
            response.setCode(400);
            response.setMessage("操作记录不存在");
            return response;
        }

        // 将改欠货数据恢复之后被改欠货的销售单的要货数还是否大于发货数
        String saleOrderId = request.getSaleOrderId();
        // 1. 获取被改欠货销售单的开单货品列表
        List<CreateGoods> creates = createGoodsService.getSaleOrderCreateGoods(saleOrderId);
        // 2. 获取被改欠货销售单的发货货品列表
        List<DeliveryGoods> deliveries = deliveryGoodsService.getSaleOrderDeliveryGoods(saleOrderId);
        // 3. 获取本动作的被改欠货货品列表
        List<ModifyGoods> modifies = modifyGoodsService.getSaleOrderModifyGoodsOfParent(request.getActionId());
        // 判断每个SKU的(要货数 - 改欠货数 - 发货数 >= 0)
        // 定义一个Map
        Map<String, BigDecimal> map = new HashMap<>();
        // 1. 把要货数放进去
        Map<String, BigDecimal> m = creates.stream().map(CreateGoods::getSkus).flatMap(Collection::stream).collect(Collectors.toMap(CreateGoodsSKU::getSkuId, CreateGoodsSKU::getQuantity));
        map.putAll(m);
        // 2. 减去改欠货数
        modifies.stream().map(ModifyGoods::getSkus).flatMap(Collection::stream).forEach(sku -> {
            BigDecimal quantity = map.get(sku.getSkuId());
            if (quantity == null) return;
            quantity = quantity.subtract(sku.getQuantity());
            map.put(sku.getSkuId(), quantity);
        });
        // 3. 减去发货数
        deliveries.stream().map(DeliveryGoods::getSkus).flatMap(Collection::stream).forEach(sku -> {
            BigDecimal quantity = map.get(sku.getSkuId());
            if (quantity == null) return;
            quantity = quantity.subtract(sku.getQuantity());
            map.put(sku.getSkuId(), quantity);
        });
        // 4. 判断每个value是否依然大于BigDecimal.ZERO
        boolean denied = map.values().stream().anyMatch(value -> value.compareTo(BigDecimal.ZERO) < 0);
        // 如果不满足
        if (denied) {
            response.setCode(400);
            response.setMessage("已发货数将大于要货数!");
            return response;
        }

        String orderId = request.getSaleOrderId();
        String actionId = request.getActionId();
        String userId = request.getUserId();
        return saleOrderActionService.doAtomically(() -> {
            // 撤销销售单的改本单动作主记录
            saleOrderActionService.cancel(actionId, userId);
            // 撤销销售单改本单动作子记录
            saleOrderActionService.cancelChildren(actionId, userId);
            // 删除改本单货品
            modifyGoodsService.deleteForSaleOrderModifyAction(actionId, userId);

            // 改我单的改他单动作主记录
            SaleOrderAction parent = saleOrderActionService.selectBy(ActionType.MODIFY_THAT, orderId);
            // 撤销改我单的改他单动作主记录
            saleOrderActionService.cancel(parent.getId(), userId);
            // 撤销改我单的改他单动作子记录
            saleOrderActionService.cancelChildren(parent.getId(), userId);

            //@TODO 重新计算销售单二级数据

            return response;
        });
    }


    /**
     * 撤销退货货品
     *
     * @param request 撤销动作货品请求
     * @return 撤销动作货品结果
     */
    @RequestMapping(value = "/return-goods", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelReturnGoods(
            SaleOrderActionCancelRequest request
    ) {
        String actionId = request.getActionId();
        String userId = request.getUserId();
        return saleOrderActionService.doAtomically(() -> {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

            if (action == null || action.getActionType() != ActionType.RETURN) {
                response.setCode(400);
                response.setMessage("操作记录不存在");
                return response;
            }

            // 撤销销售单开单货品动作主记录
            saleOrderActionService.cancel(actionId, userId);
            // 撤销销售单开单货品动作子记录
            saleOrderActionService.cancelChildren(actionId, userId);

            // 删除开单货品
            returnGoodsService.deleteForSaleOrderReturnAction(actionId, userId);
            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

    /**
     * 撤销汇款记录
     *
     * @param request 撤销动作汇款记录请求
     * @return 撤销动作汇款记录结果
     */
    @RequestMapping(value = "/remittances", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelRemittance(
            SaleOrderActionCancelRequest request
    ) {
        return saleOrderActionService.doAtomically(() -> {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

            if (action == null || action.getActionType() != ActionType.REMITTANCE) {
                response.setCode(400);
                response.setMessage("操作记录不存在");
                return response;
            }

            // 撤销
            saleOrderActionService.cancel(request.getActionId(), request.getUserId());

            // 删除
            String remittanceId = action.getActionId();
            remittanceService.cancel(remittanceId, request.getUserId());

            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

    /**
     * 撤销销售单核销记录
     *
     * @param request 撤销销售单核销记录请求
     * @return 撤销销售单核销记录结果
     */
    @RequestMapping(value = "/clearances", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelClearance(
            SaleOrderActionCancelRequest request
    ) {
        return saleOrderActionService.doAtomically(() -> {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

            if (action == null || (action.getActionType() != ActionType.CLEARANCE_IN && action.getActionType() != ActionType.CLEARANCE_OUT)) {
                response.setCode(400);
                response.setMessage("操作记录不存在");
                return response;
            }

            // 撤销
            saleOrderActionService.cancel(request.getActionId(), request.getUserId());

            // 撤销另外一条对应的核销动作
            SaleOrderAction other = saleOrderActionService.selectBy(action.getActionType() == ActionType.CLEARANCE_IN ? ActionType.CLEARANCE_OUT : ActionType.CLEARANCE_IN, action.getActionId());
            saleOrderActionService.cancel(other.getId(), request.getUserId());

            // 删除
            String clearanceId = action.getActionId();
            clearanceService.cancel(clearanceId, request.getUserId());

            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

    /**
     * 撤销销售单发货记录
     *
     * @param request 撤销销售单发货记录请求
     * @return 撤销销售单发货记录结果
     */
    @RequestMapping(value = "/deliveries", method = RequestMethod.DELETE)
    @ResponseBody
    public SaleOrderActionCancelResponse cancelDelivery(
            SaleOrderActionCancelRequest request
    ) {
        return saleOrderActionService.doAtomically(() -> {
            SaleOrderActionCancelResponse response = new SaleOrderActionCancelResponse();
            SaleOrderAction action = saleOrderActionService.selectById(request.getActionId());

            if (action == null || action.getActionType() != ActionType.DELIVERY) {
                response.setCode(400);
                response.setMessage("操作记录不存在");
                return response;
            }

            // 撤销
            saleOrderActionService.cancel(request.getActionId(), request.getUserId());

            // 撤销销售单的发货货品操作记录
            String deliveryId = action.getActionId();
            String saleOrderId = request.getSaleOrderId();
            List<SaleOrderAction> actions = saleOrderActionService.getSaleOrderDeliveryGoodsActions(
                    saleOrderId,
                    deliveryId
            );
            actions.forEach(act -> saleOrderActionService.cancel(act.getId(), request.getUserId()));

            String[] deliveryGoodsIds = actions.stream().map(SaleOrderAction::getActionId).collect(Collectors.toList()).toArray(new String[0]);
            // 撤销发货单的该销售单的发货货品记录
            deliveryGoodsService.cancel(request.getUserId(), deliveryGoodsIds);
            deliveryActionService.cancel(deliveryId, request.getUserId(), deliveryGoodsIds);

            //@TODO 重新计算销售单二级数据

            return response;
        });
    }

}
